package com.xinqi.modules.sys.gpt.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSONObject;
import com.xinqi.common.base.error.CommonErrors;
import com.xinqi.common.base.response.R;
import com.xinqi.common.core.constant.ConfigKeyConstants;
import com.xinqi.common.core.constant.GptConstants;
import com.xinqi.common.core.enums.ChatGptRoleEnum;
import com.xinqi.common.core.enums.RegisterReturnEnum;
import com.xinqi.common.core.utils.MessageUtils;
import com.xinqi.common.core.utils.PlaceholderUtils;
import com.xinqi.common.green.enums.GreenScanSuggestionEnum;
import com.xinqi.common.green.utils.SensitiveWordUtils;
import com.xinqi.modules.sys.config.service.ISysConfigService;
import com.xinqi.modules.sys.gpt.domain.DayCountEntity;
import com.xinqi.modules.sys.gpt.dto.req.ChatMessageHistoryDTO;
import com.xinqi.modules.sys.gpt.dto.req.ChatMessageRemoveDTO;
import com.xinqi.modules.sys.gpt.dto.req.ChatMessageSendDTO;
import com.xinqi.modules.sys.gpt.dto.req.ChatMessageStopDTO;
import com.xinqi.modules.sys.gpt.dto.req.Context;
import com.xinqi.modules.sys.gpt.dto.req.Messages;
import com.xinqi.modules.sys.gpt.dto.rsp.ChatMessageHistoryResultDTO;
import com.xinqi.modules.sys.gpt.dto.rsp.ChatMessageResultDTO;
import com.xinqi.modules.sys.gpt.manager.DayCountManager;
import com.xinqi.modules.sys.gpt.service.ChatMessageService;
import com.xinqi.modules.sys.gpt.util.HttpUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;


/**
 * 新奇AI消息
 *
 * @Author：yyzhen
 * @Package：com.xinqi.modules.sys.gpt.service.impl
 * @Project：XingqiClass-Cloud-Plus
 * @name：ChatMessageServiceImpl
 * @Date：2023/5/29 11:12
 * @Filename：ChatMessageServiceImpl
 */
@Log4j2
@Service("chatMessageService")
@RequiredArgsConstructor
public class ChatMessageServiceImpl implements ChatMessageService {

    private final DayCountManager dayCountManager;

    private final ISysConfigService sysConfigService;

    /**
     * 新奇AI消息 -- 发送
     * <p>
     * 200发送成功
     * 210没有次数可以分享
     * 211没有次数并且分享已达上限
     * 212有敏感词汇
     *
     * @param dto
     * @return
     */
    @Override
    public R<ChatMessageResultDTO> sendMessage(ChatMessageSendDTO dto) {
        dto.setUserSessionId(StringUtils.isEmpty(dto.getClient()) ? dto.getUserId() : dto.getClient());
        //敏感词校验
        if (!SensitiveWordUtils.checkSensitiveWord(dto.getContent())) {
            return R.error(RegisterReturnEnum.CONTAINS_SENSITIVE_ATTRIBUTES.getCode(), MessageUtils.message("green.submit.text.message"));
        }
        //配额计算
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(dto.getUserId()), MessageUtils.message("user.id.not.black"));
        synchronized (dto.getUserId().intern()) {
            DayCountEntity count = dayCountManager.findByUserAndInit(Long.parseLong(dto.getUserId()));
            //可用次数
            Integer availableCount = count.getAvailableCount();
            //已用次数
            Integer usedCount = count.getUsedCount();
            //每日次数 -- 最大值
            if (GptConstants.DEFAULT_MAX_QUOTA <= usedCount) {
                return R.error(RegisterReturnEnum.GPT_DEFAULT_MAX_QUOTA.getCode(), MessageUtils.message("gpt.day.count.use.default.completion"));
            }
            if (Objects.isNull(availableCount) || Objects.equals(0, availableCount)) {
                return R.error(RegisterReturnEnum.GPT_USED_COUNT.getCode(), MessageUtils.message("gpt.day.count.use.completion"));
            }
            if (availableCount <= usedCount) {
                return R.error(RegisterReturnEnum.GPT_USED_COUNT.getCode(), MessageUtils.message("gpt.day.count.use.completion"));
            }
            //使用成功
            count.setUsedCount(usedCount + 1);
            dayCountManager.updateById(count);
        }

        ChatMessageResultDTO result = new ChatMessageResultDTO();
        //获取连接地址
        String chatGptUrl = sysConfigService.selectConfigByKey(ConfigKeyConstants.CHAT_GPT_URL);
        //获取token
        String chatGptToken = sysConfigService.selectConfigByKey(ConfigKeyConstants.CHAT_GPT_TOKEN);
        try {
            //发送
            dto.setClient(null);
            //流输出
            dto.setStream(Boolean.TRUE);
            //预设问题封装
            dto.setContext(presets());
            JSONObject success = JSONObject.parseObject(HttpUtils.postData(chatGptUrl + GptConstants.SEND_MESSAGE_URL, HttpUtils.entityToMap(dto), GptConstants.AUTHORIZATION_BEARER + chatGptToken));
            result = JSONObject.parseObject(success.toJSONString(), ChatMessageResultDTO.class);
        } catch (Exception e) {
            log.error("消息发送失败，请稍后重试", e);
            this.recoveryByUser(Long.parseLong(dto.getUserId()));
            CommonErrors.BAD_REQUEST.check(false, MessageUtils.message("gpt.chat.meassage.send.fail"));
        }

        return R.ok(result);
    }

    /**
     * 新奇AI消息 -- 历史消息
     *
     * @param dto
     * @return
     */
    @Override
    public ChatMessageHistoryResultDTO historyMessage(ChatMessageHistoryDTO dto) {
        ChatMessageHistoryResultDTO result = new ChatMessageHistoryResultDTO();
        //获取连接地址
        String chatGptUrl = sysConfigService.selectConfigByKey(ConfigKeyConstants.CHAT_GPT_URL);
        //获取token
        String chatGptToken = sysConfigService.selectConfigByKey(ConfigKeyConstants.CHAT_GPT_TOKEN);
        try {
            JSONObject success = JSONObject.parseObject(HttpUtils.sendGet(chatGptUrl + GptConstants.HISTORY_MESSAGE_URL, HttpUtils.entityToUrlParam(dto), GptConstants.AUTHORIZATION_BEARER + chatGptToken));
            result = JSONObject.parseObject(success.toJSONString(), ChatMessageHistoryResultDTO.class);
            result.getItems().forEach(item -> {
                //角色判断为GPT回复的信息
                if (Objects.equals(ChatGptRoleEnum.ASSISTANT.getCode(), item.getRole())) {
                    Map<String, Object> attributes = item.getAttributes();
                    if (CollectionUtil.isNotEmpty(attributes)) {
                        if (Objects.equals(GreenScanSuggestionEnum.BLOCK.getCode(), attributes.get(GptConstants.ATTRIBUTE_MESSAGE_KEY))) {
                            // item.setContent(MessageUtils.message("gpt.chat.message.reply.is.sensitive"));
                            String newContent = SensitiveWordUtils.checkReplaceSensitiveWord(item.getContent());
                            if (Objects.nonNull(newContent)) {
                                item.setContent(newContent);
                            }
                        }
                    }
                }
            });
        } catch (Exception e) {
            log.error("获取消息历史记录失败，请稍后重试", e);
            CommonErrors.BAD_REQUEST.check(false, MessageUtils.message("gpt.chat.meassage.history.fail"));
        }
        return result;
    }

    /**
     * 新奇AI消息 -- 删除
     *
     * @param dto
     */
    @Override
    public void removeMessage(ChatMessageRemoveDTO dto) {
        CommonErrors.BAD_REQUEST.check(CollectionUtil.isNotEmpty(dto.getMessageIds()), MessageUtils.message("gpt.chat.meassage.messageId.not.blank"));
        //获取连接地址
        String chatGptUrl = sysConfigService.selectConfigByKey(ConfigKeyConstants.CHAT_GPT_URL);
        //获取token
        String chatGptToken = sysConfigService.selectConfigByKey(ConfigKeyConstants.CHAT_GPT_TOKEN);
        try {
            dto.getMessageIds().forEach(id ->
                HttpUtils.sendDelete(chatGptUrl + GptConstants.REMOVE_MESSAGE_URL + id, "", GptConstants.AUTHORIZATION_BEARER + chatGptToken)
            );
        } catch (Exception e) {
            log.error("删除消息失败，请稍后重试", e);
            CommonErrors.BAD_REQUEST.check(false, MessageUtils.message("gpt.chat.meassage.remove.fail"));
        }
    }

    /**
     * 新奇AI消息 -- 结束回复接口
     *
     * @param dto
     */
    @Override
    public void stopMessage(ChatMessageStopDTO dto) {
        CommonErrors.BAD_REQUEST.check(StringUtils.isNotEmpty(dto.getMessageId()), MessageUtils.message("gpt.chat.meassage.messageId.not.blank"));
        //获取连接地址
        String chatGptUrl = sysConfigService.selectConfigByKey(ConfigKeyConstants.CHAT_GPT_URL);
        //获取token
        String chatGptToken = sysConfigService.selectConfigByKey(ConfigKeyConstants.CHAT_GPT_TOKEN);
        try {
            HttpUtils.sendPost(chatGptUrl + GptConstants.STOP_MESSAGE_URL, HttpUtils.entityToUrlParam(dto), GptConstants.AUTHORIZATION_BEARER + chatGptToken);
        } catch (Exception e) {
            log.error("结束回复失败，请稍后重试", e);
            CommonErrors.BAD_REQUEST.check(false, MessageUtils.message("gpt.chat.meassage.stop.fail"));
        }
    }

    /**
     * 请求失败-- 回调 -- 恢复一次配额
     *
     * @param userId
     */
    @Override
    public void recoveryByUser(Long userId) {
        dayCountManager.recoveryByUser(userId);
    }

    /**
     * 回调 -- 回复包含敏感内容
     *
     * @param mesageId
     */
    @Override
    public void attributeMessage(String mesageId) {
        CommonErrors.BAD_REQUEST.check(StringUtils.isNotEmpty(mesageId), MessageUtils.message("gpt.chat.meassage.messageId.not.blank"));
        //获取连接地址
        String chatGptUrl = sysConfigService.selectConfigByKey(ConfigKeyConstants.CHAT_GPT_URL);
        //获取token
        String chatGptToken = sysConfigService.selectConfigByKey(ConfigKeyConstants.CHAT_GPT_TOKEN);
        try {
            String attributeUrl = PlaceholderUtils.replaceWithVarargs(GptConstants.ATTRIBUTE_MESSAGE_URL, mesageId, GptConstants.ATTRIBUTE_MESSAGE_KEY);
            Map<String, Object> param = new HashMap<>();
            param.put("value", GreenScanSuggestionEnum.BLOCK.getCode());
            HttpUtils.putData(chatGptUrl + attributeUrl, param, GptConstants.AUTHORIZATION_BEARER + chatGptToken);
        } catch (Exception e) {
            log.error("回调失败，请稍后重试", e);
            CommonErrors.BAD_REQUEST.check(false, MessageUtils.message("gpt.chat.meassage.attribute.fail"));
        }
    }

    /**
     * 预设问题封装
     *
     * @return
     */
    private Context presets() {
        List<Messages> messages = new ArrayList<>();
        messages.add(new Messages(ChatGptRoleEnum.SYSTEM.getCode(),
            "你是上海东双合信息服务有限公司研发的一款教学工具，公司网址是www.xinqiclass.com。  "));
        messages.add(new Messages(ChatGptRoleEnum.SYSTEM.getCode(),
            "你是新奇课堂教学工具，名字是“新奇问问”。"));
        messages.add(new Messages(ChatGptRoleEnum.SYSTEM.getCode(),
            "若回复涉及中国政府负面信息，则“回复该内容含有敏感信息，请提问其他合法内容。”。"));
        messages.add(new Messages(ChatGptRoleEnum.SYSTEM.getCode(),
            "涉及到公司老板、创始人、BOSS信息，则回复：您好，此类信息请前往新奇课堂官网查询，官网地址：www.xinqiclass.com"));
        return new Context(messages);

    }

}
